package com.dbms.parser;

import com.dbms.common.Constants;
import com.dbms.common.SqlError;
import com.dbms.parser.ast.*;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * SQL执行计划生成器
 * 负责将解析得到的抽象语法树（AST）转换为结构化的执行计划
 * 支持多种SQL语句类型（CREATE TABLE、INSERT、SELECT、DELETE、UPDATE等）
 * 执行计划清晰展示SQL的执行步骤和层次关系，便于后续优化和执行
 */
public class ExecutionPlanGenerator {
    // 存储执行计划生成过程中产生的错误信息（如不支持的语句类型、语法错误等）
    private List<SqlError> errors;

    /**
     * 构造方法：初始化错误信息列表
     */
    public ExecutionPlanGenerator() {
        this.errors = new ArrayList<>();
    }

    /**
     * 为多个SQL语句生成对应的执行计划
     * @param statements 解析得到的SQL语句抽象语法树节点列表
     * @return 每个SQL语句对应的执行计划字符串列表（生成失败的语句不会被包含）
     */
    public List<String> generatePlans(List<StatementNode> statements) {
        List<String> plans = new ArrayList<>();
        // 遍历每个语句节点，生成对应的执行计划
        for (StatementNode statement : statements) {
            String plan = generatePlan(statement);
            if (plan != null) {
                plans.add(plan);
            }
        }
        return plans;
    }

    /**
     * 为单个SQL语句生成执行计划（核心分发方法）
     * 根据语句类型调用对应的计划生成方法
     * @param stmt 单个SQL语句的抽象语法树节点
     * @return 该语句的执行计划字符串；若生成失败或不支持该类型，返回null
     */
    private String generatePlan(StatementNode stmt) {
        if (stmt == null) {
            return null;
        }

        // 根据语句类型分发到具体的计划生成方法
        switch (stmt.getStatementType()) {
            case "CREATE_TABLE":
                return generateCreateTablePlan((CreateTableNode) stmt);
            case "INSERT":
                return generateInsertPlan((InsertNode) stmt);
            case "SELECT":
                return generateSelectPlan((SelectNode) stmt);
            case "DELETE":
                return generateDeletePlan((DeleteNode) stmt);
            case "UPDATE": // 【新增】支持UPDATE语句的执行计划生成
                return generateUpdatePlan((UpdateNode) stmt);
            default:
                // 记录不支持的语句类型错误
                errors.add(new SqlError(
                        Constants.ErrorType.SEMANTIC_ERROR,
                        stmt.getPosition(),
                        "不支持的语句类型: " + stmt.getStatementType()
                ));
                return null;
        }
    }

    /**
     * 生成CREATE TABLE语句的执行计划
     * @param node CREATE TABLE语句的抽象语法树节点
     * @return 包含表名和列信息的创建表执行计划
     */
    private String generateCreateTablePlan(CreateTableNode node) {
        StringBuilder plan = new StringBuilder();
        plan.append("CreateTable {\n")
                .append("    tableName: '").append(node.getTableName()).append("',\n")
                .append("    columns: [\n");

        // 拼接所有列的定义（名称和类型）
        for (com.dbms.catalogInParse.Column col : node.getColumns()) {
            plan.append("        {name: '").append(col.getName())
                    .append("', type: '").append(col.getType()).append("'},\n");
        }

        plan.append("    ]\n")
                .append("}");
        return plan.toString();
    }

    /**
     * 生成INSERT语句的执行计划
     * @param node INSERT语句的抽象语法树节点
     * @return 包含表名、目标列和插入行数的插入执行计划
     */
    private String generateInsertPlan(InsertNode node) {
        StringBuilder plan = new StringBuilder();
        plan.append("InsertPlan {\n");
        plan.append("  tableName: ").append(node.getTableName()).append("\n");

        // 若指定了目标列，添加列信息
        if (!node.getColumnNames().isEmpty()) {
            plan.append("  columns: ").append(node.getColumnNames()).append("\n");
        }

        // 添加插入的行数信息
        plan.append("  valuesCount: ").append(node.getValues().size()).append("行\n");
        plan.append("}");
        return plan.toString();
    }

    /**
     * 生成SELECT语句的执行计划（支持嵌套结构）
     * 按照从底层到顶层的顺序构建计划：数据扫描/连接 → 过滤 → 聚合 → 排序 → 投影
     * @param node SELECT语句的抽象语法树节点
     * @return 多层嵌套的查询执行计划
     */
    // 【核心改造】重写Select计划生成，使其支持嵌套
    private String generateSelectPlan(SelectNode node) {
        String basePlan;

        // 最底层：处理表扫描或连接操作
        if (node.getJoinNode() != null) {
            // 若存在连接，生成嵌套循环连接计划
            basePlan = String.format(
                    "NestedLoopJoinPlan {\n" +
                            "  left: SeqScanPlan { tableName: %s },\n" +
                            "  right: SeqScanPlan { tableName: %s },\n" +
                            "  on: %s\n" +
                            "}", node.getTableName(), node.getJoinNode().getRightTable(), node.getJoinNode().getOnCondition()
            );
        } else {
            // 无连接时，生成简单的顺序扫描计划
            basePlan = String.format("SeqScanPlan { tableName: %s }", node.getTableName());
        }

        // 中间层1：处理WHERE条件过滤
        if (node.getWhereClause() != null) {
            basePlan = String.format(
                    "FilterPlan {\n" +
                            "  condition: %s,\n" +
                            "  child: %s\n" +
                            "}", node.getWhereClause(), indent(basePlan)
            );
        }

        // 【新增】中间层2：处理GROUP BY聚合操作
        if (node.getGroupByNode() != null) {
            basePlan = String.format(
                    "AggregatePlan {\n" +
                            "  groupBy: %s,\n" +
                            "  child: %s\n" +
                            "}", node.getGroupByNode().getColumns(), indent(basePlan)
            );
        }

        // 【新增】中间层3：处理ORDER BY排序操作
        if (node.getOrderByNode() != null) {
            basePlan = String.format(
                    "SortPlan {\n" +
                            "  orderBy: %s %s,\n" +
                            "  child: %s\n" +
                            "}", node.getOrderByNode().getColumns(), node.getOrderByNode().getOrder(), indent(basePlan)
            );
        }

        // 最顶层：处理SELECT投影（指定返回列）
        return String.format(
                "ProjectPlan {\n" +
                        "  columns: %s,\n" +
                        "  child: %s\n" +
                        "}", node.getColumns(), indent(basePlan)
        );
    }

    /**
     * 生成DELETE语句的执行计划
     * @param node DELETE语句的抽象语法树节点
     * @return 包含表名和删除条件的删除执行计划
     */
    private String generateDeletePlan(DeleteNode node) {
        StringBuilder plan = new StringBuilder();
        plan.append("DeletePlan {\n");
        plan.append("  tableName: ").append(node.getTableName()).append("\n");

        // 添加删除条件（WHERE子句），若无则说明删除所有记录
        if (node.getWhereClause() != null) {
            plan.append("  condition: ").append(node.getWhereClause()).append("\n");
        } else {
            plan.append("  condition: 删除所有记录\n");
        }

        plan.append("}");
        return plan.toString();
    }

    /**
     * 【新增】生成UPDATE语句的执行计划
     * @param node UPDATE语句的抽象语法树节点
     * @return 包含表名、更新字段和更新条件的更新执行计划
     */
    private String generateUpdatePlan(UpdateNode node) {
        // 将更新字段列表转换为字符串
        String setClauses = node.getSetClause().stream()
                .map(ExpressionNode::toString)
                .collect(Collectors.joining(", "));

        StringBuilder plan = new StringBuilder();
        plan.append("UpdatePlan {\n");
        plan.append("  tableName: ").append(node.getTableName()).append(",\n");
        plan.append("  set: [").append(setClauses).append("],\n");

        // 添加更新条件（WHERE子句），若无则说明更新所有记录
        if (node.getWhereClause() != null) {
            plan.append("  condition: ").append(node.getWhereClause()).append("\n");
        } else {
            plan.append("  condition: 更新所有记录\n");
        }

        plan.append("}");
        return plan.toString();
    }

    /**
     * 辅助函数：对执行计划字符串进行缩进处理
     * 用于美化嵌套结构的显示，使计划层次更清晰
     * @param text 待缩进的执行计划文本
     * @return 每行前添加缩进的文本
     */
    private String indent(String text) {
        return text.lines().map(line -> "  " + line).collect(Collectors.joining("\n"));
    }

    /**
     * 获取执行计划生成过程中收集的错误信息
     * @return 错误信息列表
     */
    public List<SqlError> getErrors() {
        return errors;
    }
}